/*
 * 	SMacLayer.cc
 *
 *  Created on: 20/3/2011
 *  Author: Charlie (Yong zha)
 *  This is a implement of Smac protocal .
 */

/****protocal config **********/
#define SMAC_HEARDLENGTH   272
#define LENGTH_SYNS 200
#define LENGTH_RTS	160
#define LENGTH_CTS	160
#define LENGTH_ACK  112
#define DELAY 20
/****contend time  **********/
#define SYNC_CONTEND_TIME	20
#define RTS_CONTEND_TIME	1
#define CTS_CONTEND_TIME	5
#define DATA_CONTEND_TIME	5
#define ACK_CONTEND_TIME	5

#define ALLOWED_DRIFT		30

#define RESYNC_LOW	100
#define RESYNC_HIGH	200
/****other config   **********/
#define MAX_MSG_LEN 18496

#include "RealTimeSMACLayer.h"
#include "RSMacMsg_m.h"
#include "sensor_m.h"
#include <BaseArp.h>
#include <MacToPhyControlInfo.h>
#include <MacToNetwControlInfo.h>
#include <PhyToMacControlInfo.h>
#include <NetwToMacControlInfo.h>
#include <SimpleAddress.h>
#include <BaseConnectionManager.h>

Define_Module(RealTimeSMACLayer);

void RealTimeSMACLayer::initialize(int stage)
{
	BaseMacLayer::initialize(stage);
	 if (stage == 0)
	{
		EV << "Smaclayer Initializing stage 0\n";
		clock_skew = uniform(0.0, 1.0)*10;
		// initial parameters
		txPower = hasPar("txPower") ? par("txPower").doubleValue() : 110.11;
		listen_time = hasPar("listen_time") ? par("listen_time").longValue() :500;
		frame_time = hasPar("frame_time") ? par ("frame_time").longValue() : 20000;
		assert(frame_time >= listen_time);
		sleep_time = frame_time - listen_time;
		bitrate = hasPar("bitrate")?par("bitrate").longValue():9600;
		centerFreq = hasPar("centerFrequency") ?
					par("centerFrequency").doubleValue() : 2.412e9;
		allowDrift = hasPar("allowDrift") ?
				par("allowDrift").doubleValue() : 30;
		queueLength = hasPar("queueLength") ? par("queueLength") : 10;

		aTurnaroundTime = par("aTurnaroundTime").doubleValue();
		//timers default number is 5 .
		int i;
		char buffer[] = "mac timeout i";
		for(i=0; i<TIMERS; i++) {
			buffer[12] = '0'+i;
			timeout_msg[i] = new cMessage(buffer);
		}
		contention = new ChannelSenseRequest("contention", MacToPhyInterface::CHANNEL_SENSE_REQUEST);
		contention->setSenseMode(UNTIL_BUSY);

		/******Initialize scalars*********/
		nb_contend_fail = 0;
		nb_buffer_full_drop = 0;
		nb_net_package = 0;
		for(int i = 0;i<=PRIORITY_LNUM;i++){
			net_package[i] = 0;
		}
		nb_received_nav = 0;

		/******Initialize flags **********/
		is_transmitting = false;

	} else if(stage == 1) {
		fsc = 0 ; //frame sequence counter
		must_send_sync = 0;
		must_resort = false;
		sched_count = 0;
		sched_state = SCHED_STATE_STARTUP;
		time_last_sched = 0;
		proto_state = PROTO_STATE_IDLE;
		proto_next_state = PROTO_STATE_INVALID;
		nav_state = NAV_CLEAR;
		nav_end_time = 0;
		my_serial = 1;
		simtime_t syncat = intuniform(1,10)*frame_time;
		setSchedTimeout(syncat);

		//display to debug
		EV<<"listen_time = " <<listen_time <<endl;
		EV<<"frame_time = " <<frame_time <<endl;
		EV<<"sleep_time = " <<sleep_time <<endl;
		EV<<"bitrate = " <<bitrate <<endl;
		EV<<"clock_skew = " <<clock_skew <<endl;
		EV<<"MacAdd = " <<myMacAddr <<endl;
		EV<<"bufferlen = " <<queueLength <<endl;
	}
}

void RealTimeSMACLayer::setMySchedule(simtime_t time)
{
	// my frame will start in <time>, which means it
	// started at <time>-<frame_time>
	assert(time < frame_time);
	time_last_sched = simTime() + time - frame_time;
	must_send_sync = 1;
	//resync_counter = intuniform(RESYNC_LOW/frame_time, RESYNC_HIGH/frame_time);
	calcSchedState();
}

void RealTimeSMACLayer::setIdle()
{
	proto_state = PROTO_STATE_IDLE;
	calcSchedState();
	evalState();
}

void RealTimeSMACLayer::handleUpperMsg(cMessage* msg)
{
	cPacket* pkt = static_cast<cPacket*>(msg);
	Sensor* sensorData = static_cast<Sensor*>(msg);
	++nb_net_package;
	EV << "Smac::handleUpperMsg " << msg->getName() << "\n";
	if (pkt->getBitLength() > MAX_MSG_LEN){
	        error("packet from higher layer (%s)%s is too long for Smac, %d bytes (fragmentation is not supported yet)",
	              pkt->getClassName(), pkt->getName(), pkt->getByteLength());
	delete msg;
	}

	//nb_net_package[sensorData->getPriorty()]++;

	// I don't set a buffer for the packets ?
	//I will add a buffer there when I figure out how to resend the blocked msg
	if (tx_msgQuene.size() < queueLength) {
			//check if it is selfmsg
			NetwToMacControlInfo* cInfo = static_cast<NetwToMacControlInfo*>(
					msg->getControlInfo());
		    if(cInfo->getNextHopMac()==myMacAddr){
		    	EV<<"Self Msg , only delete" <<endl;
		    	delete msg;
		    	return;
		    }
			RSMacMsg* tx_msg = encapsMsg(pkt);
			tx_msg->setPriorty(sensorData->getPriorty());
			tx_msgQuene.push_back(tx_msg);
			must_resort = true;
			EV << "Max queue length: " << queueLength << ", packet put in queue\n  queue size: "
						<< tx_msgQuene.size()<< endl;

	}else {
			// queue is full, message has to be deleted
			EV << "New packet arrived, but queue is FULL, so new packet is deleted\n";
			cMessage* msgReply = new cMessage();
			msgReply->setName("MAC ERROR");
			msgReply->setKind(PACKET_DROPPED);
			RSMacMsg* lastMsg = tx_msgQuene.back();
			nb_buffer_full_drop ++ ;
			if(lastMsg->getPriorty() > sensorData->getPriorty()){
				dumpQueue("replace");
				tx_msgQuene.pop_back();
				msgReply->setSchedulingPriority(lastMsg->getPriorty());
				RSMacMsg* tx_msg = encapsMsg(pkt);
				tx_msg->setPriorty(sensorData->getPriorty());
				tx_msgQuene.push_back(tx_msg);

				must_resort = true;
				delete lastMsg;
			}else{
				msgReply->setSchedulingPriority(sensorData->getPriorty());
				delete msg;
			}
			sendControlUp(msgReply);
	}
	dumpQueue("outQueue");
	evalState();
	return;
}

void RealTimeSMACLayer::handleLowerMsg(cMessage* msg)
{
		assert(msg);
		if (sched_state == SCHED_STATE_SLEEP)
			return; // we're asleep, drop it
		switch (msg->getKind())
		{
			case SYN:
				receiveSync(msg);
				evalState();
				break;
			case RTS:
				receiveRts(msg);
				break;
			case CTS:
				receiveCts(msg);
				break;
			case DATA:
				receiveData(msg);
				break;
			case ACK:
				receiveAck(msg);
				break;
			default:
				delete msg;
				break;
		}
		//I think it is not useful for evaluating state here . So try it
		//evalState();

}

void RealTimeSMACLayer::handleLowerControl(cMessage* msg)
{
	EV << simTime() << " handleLowerControl " << msg->getName() << endl;
	switch(msg->getKind()) {
		case MacToPhyInterface::TX_OVER:
		   EV << "PHY indicated transmission over" << endl;
		   is_transmitting = false;
		   transmitDone();
		   delete msg;
		   break;
		case MacToPhyInterface::RADIO_SWITCHING_OVER:
			//TODO: handle this correctly (by now we assume switch times are zero)
			delete msg;
			break;
		//handle the CHANNEL_SENSE_REQUEST return ,including contention and endSifs.
		case MacToPhyInterface::CHANNEL_SENSE_REQUEST:
			if(sched_state != SCHED_STATE_SLEEP&&msg == contention) {
				protocolTimeout();
			} else {
				EV<<"Recieve sense result but I am sleeping ,so ingnore it"<<endl;
			}
			break;
		default:
			delete msg;
			break;
	}
}

void RealTimeSMACLayer::handleSelfMsg(cMessage* msg)
{
	for(int i=0; i<TIMERS; i++) {
		if(msg == timeout_msg[i]) {
			switch (i){
				case TIMER_PROTOCOL:
					protocolTimeout();
					break;
				case TIMER_NAV:
					navTimeout();
					break;
				case TIMER_SCHED:
					schedTimeout();
					break;
				default:
					assert(false);		// unknown timer
			}
		}
	}
}

void RealTimeSMACLayer::finish()
{
	recordScalar("contend_fail", nb_contend_fail);
	//recordScalar("net_package" , nb_net_package);
	recordScalar("buffer_full_drop", nb_buffer_full_drop);
	recordScalar("received_nav", nb_received_nav);
	recordScalar("percentage_duty",listen_time/frame_time);

	delayStats.recordAs("SendTime");
	contend_fail.recordAs("contend fail");
	EV<< " buffer_full_drop " << nb_buffer_full_drop << " on total " <<nb_net_package <<endl;
}

	RealTimeSMACLayer::~RealTimeSMACLayer()
{
	for(int i=0; i<TIMERS; i++) {
		cancelAndDelete(timeout_msg[i]);
	}
	SMacMsgList::iterator it;
	for(it = tx_msgQuene.begin(); it != tx_msgQuene.end(); ++it)
	{
		delete (*it);
	}
	cancelAndDelete(contention);
}

void RealTimeSMACLayer::calcSchedState()
{
	simtime_t t = simTime();
	simtime_t in_f = (simtime_t) (t - time_last_sched);
	assert(listen_time>0);
	// check if we are in our own send time (this frame)
	if ( /*in_f >=0 && */ in_f < listen_time)
	{
		EV<<"Now states is SCHED_STATE_OWN"<< endl;
		sched_state = SCHED_STATE_OWN;
		simtime_t left = listen_time + 5 - in_f;
		assert(left <= listen_time + 5);
		setSchedTimeout(left);
		return;
	}
	// check if we are in the next listen frame
	if (in_f > frame_time - 5 && in_f < frame_time + listen_time)
	{
		EV<<"Now states is SCHED_STATE_OWN"<< endl;
		time_last_sched += frame_time;
		in_f -= frame_time;
		if (in_f == 0) { //check for start of frame

			//if (resync_counter <= 0) {
			//	must_send_sync = 1;
				//resync_counter = NEW_RESYNC_COUNTER;
			//}
		}
		sched_state = SCHED_STATE_OWN;
		simtime_t left = listen_time + 5 - in_f;
		assert(left <= listen_time + 10);
		setSchedTimeout(left);
		return;
	}
	// check if we are in any other listen frame
	assert(in_f < frame_time);
	int i;
	for (i = 0; i < sched_count; i++)
	{
		if (in_f >  sched_table[i] - 5 && in_f < sched_table[i] + listen_time)
		{
			EV<<"Now states is SCHED_STATE_OTHER"<< endl;
			sched_state = SCHED_STATE_OTHER;
			simtime_t end_in_f = sched_table[i] + listen_time;
			if (end_in_f > frame_time)
			{
				// don't miss own interval
				end_in_f = frame_time;
			}
			simtime_t left = end_in_f - in_f + 5;
			assert(left <= listen_time + 10);
			setSchedTimeout(left);
			return;
		}
	}
	//Check if we are transmitting data
	if(is_transmitting){
		return ;   //just return and wait for the transmitting done
	}
	// not in any listen frame. calc sleep time
	sched_state = SCHED_STATE_SLEEP;
	proto_state = PROTO_STATE_IDLE;   //for next cycle to resend date
	simtime_t wake_at = frame_time;	// at most to own frame
	// check if there is a frame that starts earlier
	for (i = 0; i < sched_count; i++)
	{
		if (sched_table[i] > in_f && sched_table[i] < wake_at)
			wake_at = sched_table[i];
	}
	simtime_t left = wake_at - in_f;
	assert(left <= sleep_time);
	cancelTimeout(TIMER_PROTOCOL);
	setSchedTimeout(left);
	switchRadio(Radio::SLEEP);
	EV<<"Duty Cycle ending ,Now go to Sleep,I will wake up after "<< left << "s" <<endl;
	return;
}

void RealTimeSMACLayer::evalState()
{
	if (proto_state == PROTO_STATE_IDLE ){
		if(must_resort){
			tx_msgQuene.sort(RealTimeSMACLayer::prorityComp);
			must_resort = false;
			dumpQueue("after Sort");
		}
		// idling
		if (nav_state == NAV_CLEAR && sched_state != SCHED_STATE_SLEEP){
			// listening / active state
			if (must_send_sync){
				// start contending
				proto_next_state = PROTO_STATE_SEND_SYNC;
				startContending(SYNC_CONTEND_TIME);
				return;
			}
			if ((tx_msgQuene.size()>0) && sched_state == SCHED_STATE_OWN){
				if (tx_msgQuene.front()->getDestAddr()!=-1){
					// not broadcast msg so start contending for CA
					proto_next_state = PROTO_STATE_SEND_RTS;
					startContending(RTS_CONTEND_TIME+tx_msgQuene.front()->getPriorty());
				}else{
					//broadcast msg so start without CA
					EV<<"broadcast msg so just send it" << endl;
					proto_next_state = PROTO_STATE_SEND_DATA;
					startContending(DATA_CONTEND_TIME);
				}
				return;
			}
			// nothing to do, listen
			switchRadio(Radio::RX);
		}else{
			// sleep state
			if(nav_state != NAV_CLEAR)
				EV<<"NAV is not clear" << endl;
			else
				EV<<"I am sleeping now" << endl;
		}
	} else{
		EV<<"I am not idle now , so I need finish my job first" << endl;
	}


}


void RealTimeSMACLayer::startContending(int time)
{
	assert(proto_next_state >= 0);	// must have something todo
	assert(time >= 1);
	is_transmitting = true;
	int ctime;
	switchRadio(Radio::RX);
	if (nav_state == NAV_BUSY){
		proto_next_state = PROTO_STATE_INVALID;
		setIdle();
	}else{
		proto_state = PROTO_STATE_CONTEND;
		if(PROTO_STATE_SEND_RTS == proto_next_state)
			ctime = (int) intuniform(time, time+2);	//for the exactly contend time
		else
			ctime = (int) intuniform(1, time);
		contention->setSenseTimeout(ctime);
		sendControlDown(contention);  //send senseRequest for contending
	}
}

//////////////////////Send and Recieve ///////////////////

void RealTimeSMACLayer::sendSync()
{

	EV<< "Sending Sync ......."<<endl;
	must_send_sync = 0;
	proto_state = PROTO_STATE_SEND_SYNC;
	RSMacMsg *macPkt = new RSMacMsg("sync");
	macPkt->setSrcAddr(myMacAddr);
	macPkt->setDestAddr(-1);
	macPkt->setKind(SYN);
	macPkt->setBitLength(LENGTH_SYNS);
	simtime_t sendTime = macPkt->getBitLength() / bitrate;
	simtime_t stime = time_last_sched + frame_time		// time of next frame
									- simTime();
							//- sendTime;			// SendTime
	macPkt->setStime(stime);
	attachSignal(macPkt,simTime()+aTurnaroundTime);
	sendDelayed(macPkt, aTurnaroundTime, lowerGateOut);
	EV<<time_last_sched<<endl;
}

void RealTimeSMACLayer::sendRts()
{
	assert(tx_msgQuene.size()>0);
	EV<<"sending rts ->" << tx_msgQuene.front()->getDestAddr() << endl;
	proto_state = PROTO_STATE_SEND_RTS;
	RSMacMsg *macPkt = new RSMacMsg("rts");
	macPkt->setSrcAddr(myMacAddr);
	macPkt->setDestAddr(tx_msgQuene.front()->getDestAddr());
	macPkt->setKind(RTS);
	macPkt->setBitLength(LENGTH_RTS);
	macPkt->setDuration(packetDuration(LENGTH_CTS+LENGTH_ACK+tx_msgQuene.front()->getBitLength(),bitrate)+
										CTS_CONTEND_TIME+DATA_CONTEND_TIME+ACK_CONTEND_TIME );
	attachSignal(macPkt,simTime()+aTurnaroundTime);
	sendDelayed(macPkt, aTurnaroundTime, lowerGateOut);
	time_sendmsg = simTime(); // for calculating time delay
	setProtocolTimeout(WaitTimeOut(CTS));

}


void RealTimeSMACLayer::sendCts()
{
	EV<<"sending cts ->" << cts_to << endl;
	proto_state = PROTO_STATE_SEND_CTS;
	RSMacMsg *macPkt = new RSMacMsg("cts");
	macPkt->setSrcAddr(myMacAddr);
	macPkt->setDestAddr(cts_to);
	macPkt->setKind(CTS);
	macPkt->setBitLength(LENGTH_CTS);
	macPkt->setDuration(cts_nav_t - packetDuration(LENGTH_CTS,bitrate)-CTS_CONTEND_TIME);  //NAV time
	attachSignal(macPkt,simTime()+aTurnaroundTime);
	sendDelayed(macPkt, aTurnaroundTime, lowerGateOut);
	setProtocolTimeout(WaitTimeOut(DATA));
}

void RealTimeSMACLayer::sendData()
{
		EV<<"sending date ->" << tx_msgQuene.front()->getDestAddr() << endl;
		proto_state = PROTO_STATE_SEND_DATA;
		RSMacMsg *macPkt = static_cast<RSMacMsg *>(tx_msgQuene.front()->dup());
		macPkt->setSrcAddr(myMacAddr);
		macPkt->setKind(DATA);
		macPkt->setDuration(packetDuration(macPkt->getBitLength()+SMAC_HEARDLENGTH, bitrate));
		macPkt->setDestAddr(tx_msgQuene.front()->getDestAddr());
		attachSignal(macPkt,simTime()+aTurnaroundTime);
	    // send DATA frame
	    sendDelayed(macPkt, aTurnaroundTime, lowerGateOut);
	    if(macPkt->getDestAddr() == -1)
	    	return;  // we don't need time out when sending broadcast
	    setProtocolTimeout(WaitTimeOut(ACK));
}

void RealTimeSMACLayer::sendAck()
{
		EV<<"sending ack ->" << ack_to << endl;
		proto_state = PROTO_STATE_SEND_ACK;
		RSMacMsg *macPkt = new RSMacMsg("ack");
		macPkt->setBitLength(LENGTH_ACK);
		macPkt->setSrcAddr(myMacAddr);
		macPkt->setKind(ACK);
		macPkt->setDuration(packetDuration(LENGTH_ACK, bitrate));
		macPkt->setDestAddr(ack_to);
		attachSignal(macPkt,simTime()+aTurnaroundTime);
		sendDelayed(macPkt, aTurnaroundTime, lowerGateOut);
	    // the dest address must be the src adress of the RTS or the DATA
	    // packet received. The src adress is the adress of the node
}


void RealTimeSMACLayer::receiveSync(cMessage * msg)
{
	RSMacMsg* msgMac = static_cast<RSMacMsg*>(msg);
	simtime_t stime = msgMac->getStime();
	assert(stime < frame_time);
	// If it is the first syn msg received , following it.
	if (sched_state == SCHED_STATE_STARTUP){
		cancelTimeout(TIMER_SCHED);
		EV<< "received SYNC, following" <<endl;
		setMySchedule(stime);
		delete msg;
		return;
	}
	// check offset
	simtime_t ftime = simTime() + stime;	// frame start time
	if (isSameSchedule(ftime, time_last_sched+frame_time)){
		EV<< "received SYNC, my own schedule"<<endl;
		delete msg;
		return;
	}
	// check other schedules
	int i;
	for (i = 0; i < sched_count; i++){
		if (isSameSchedule(ftime, time_last_sched + sched_table[i])){
			EV<<"received SYNC, known schedule" << endl;
			delete msg;
			return;
		}
	}
	// new schedule
	simtime_t offset = ftime - time_last_sched;
	if (offset < 0)
		offset = 0 - offset;
	assert(offset > 0);
	delete msg;
	adoptSchedule(offset);
}

void RealTimeSMACLayer::receiveCts(cMessage * msg)
{
	RSMacMsg* msgMac = static_cast<RSMacMsg*>(msg);
	if (msgMac->getDestAddr()==myMacAddr){
		if (proto_state == PROTO_STATE_WFCTS){
			cancelTimeout(TIMER_PROTOCOL);  //must be cannelled or system will still got the timeout message
			EV<< "received CTS not for me,Preparing to send date" <<endl;
			proto_next_state = PROTO_STATE_SEND_DATA;
			startContending(DATA_CONTEND_TIME);
		}
	}else{
		updateNav(msgMac->getDuration());//to do : there should eval all the time of a data transation but now just simple it as const time
	}
	delete msg;
}



void RealTimeSMACLayer::receiveRts(cMessage * msg)
{
	RSMacMsg* msgMac = static_cast<RSMacMsg*>(msg);
	if (msgMac->getDestAddr()==myMacAddr){
		EV<< "received RTS, preparing for cts"<<endl;
		cts_to = msgMac->getSrcAddr();
		cts_nav_t = msgMac->getDuration();
		proto_next_state = PROTO_STATE_SEND_CTS;
		startContending(CTS_CONTEND_TIME);
	}else{
		EV<< "received RTS not for me" <<endl;
		updateNav(msgMac->getDuration());	//to do :
	}
	delete msg;
}

void RealTimeSMACLayer::receiveData(cMessage * msg)
{
	RSMacMsg* msgMac = static_cast<RSMacMsg*>(msg);
	if(msgMac->getDestAddr() == myMacAddr){
		if(proto_state == PROTO_STATE_WFDATA){
			EV<< "received DATE for me ,send up" <<endl;
			cancelTimeout(TIMER_PROTOCOL);  //must be cannelled or system will still got the timeout message
			sendUp(decapsMsg(msgMac));
			ack_to = msgMac->getSrcAddr();
			proto_next_state = PROTO_STATE_SEND_ACK;
			startContending(ACK_CONTEND_TIME);
			delete msg;
		}else{
			delete msg;
		}
	}else if(msgMac->getDestAddr() == -1){
		EV<< "received BroadCast " <<endl;
		sendUp(decapsMsg(msgMac));
		delete msg;
	}else{
		//updateNav(packetDuration(LENGTH_ACK, bitrate));
		delete msg;
	}
}

void RealTimeSMACLayer::receiveAck(cMessage * msg)
{

	RSMacMsg* msgMac = static_cast<RSMacMsg*>(msg);
	if (msgMac->getDestAddr() == myMacAddr){
		if (proto_state != PROTO_STATE_WFACK ||
			msgMac->getSrcAddr() != tx_msgQuene.front()->getDestAddr()){
			EV<< "drop ack frame ,It is not for me" <<endl;
		}else{
			EV<< "received ack for me , pop msgQuene" <<endl;
			cancelTimeout(TIMER_PROTOCOL);  //must be cannelled or system will still got the timeout message
			RSMacMsg* msgfree = tx_msgQuene.front();
			tx_msgQuene.pop_front();
			delete msgfree;
			delete msg;
			setIdle();
			EV<<" receive ack time " << simTime() <<" send rts time " << time_sendmsg << endl;
			delayStats.collect(simTime()- time_sendmsg);
			//++my_serial;
		}
	}else{
		EV<< "received ack for (not me)" <<endl;
		delete msg;
	}

}

//Only Adding a new  schedule in to table
void RealTimeSMACLayer::adoptSchedule(simtime_t offset)
{
	assert(offset >= 0);
	if (sched_count < 10){
		sched_table[sched_count++] = offset;
		must_send_sync = 1;
		switch (sched_state){
			case SCHED_STATE_SLEEP:
				// ? how did i receive this
				assert(false);
			case SCHED_STATE_OWN:
			case SCHED_STATE_OTHER:
				// do nothing, calc at end of listen time
				break;
			case SCHED_STATE_STARTUP:
				assert(false);	// invalid state
		}
	}
}

Signal* RealTimeSMACLayer::createSignal(simtime_t start, simtime_t length, double power, double bitrate)
{
		simtime_t end = start + length;
		//create signal with start at current simtime and passed length
		Signal* s = new Signal(start, length);

		//create and set tx power mapping
		Mapping* txPowerMapping = createRectangleMapping(start, end, power);
		s->setTransmissionPower(txPowerMapping);

		//create and set bitrate mapping
		Mapping* bitrateMapping = createConstantMapping(start, end, bitrate);
		s->setBitrate(bitrateMapping);

		return s;
}

/////////////////TimeOut Function ///////////////////////////
void RealTimeSMACLayer::navTimeout()
{
	nav_state = NAV_CLEAR;
	evalState();
}

void RealTimeSMACLayer::schedTimeout()
{
	switch (sched_state){
		case SCHED_STATE_STARTUP:
			setMySchedule(0);
			evalState();
			break;
		default:
			calcSchedState();
			evalState();
	}
}

void RealTimeSMACLayer::protocolTimeout()
{
	int next_state;
	switch (proto_state){
		case PROTO_STATE_CONTEND:
			// contend failed restart. We needn't add reschedule time because
			//it will reschedule  after receive msg or after NAV time
			if(!contention->getResult().isIdle()){
				EV << "contenting failed ,wait for next cycle" << endl;
				if(PROTO_STATE_SEND_RTS == proto_next_state ){
					contend_fail.collect(tx_msgQuene.front()->getPriorty());
				}
				proto_state = PROTO_STATE_IDLE;
				proto_next_state = PROTO_STATE_INVALID;
				is_transmitting = false; // contending fail ,so we don't need set this flag
				nb_contend_fail++;
				return;
			}
			EV << "contenting successful" << endl;
			assert(proto_next_state >= 0);
			assert(nav_state == NAV_CLEAR);
			// take a rssi sample, to be sure
			// make sure we sample the ether GPH
			if(!phy->getChannelState().isIdle()) { // someone in the air, re-contend
				setIdle();
				is_transmitting = false; // stop to send meeage
				return;
			}
			// start the next state
			next_state = proto_next_state;
			proto_next_state = PROTO_STATE_INVALID;
			switchRadio(Radio::TX);
			switch (next_state){
				case PROTO_STATE_SEND_SYNC:
					sendSync();
					break;
				case PROTO_STATE_SEND_RTS:
					sendRts();
					break;
				case PROTO_STATE_SEND_CTS:
					sendCts();
					break;
				case PROTO_STATE_SEND_DATA:
					sendData();
					break;
				case PROTO_STATE_SEND_ACK:
					sendAck();
					break;
				default:
					assert(false);	// invalid
			}
			break;
		case PROTO_STATE_WFCTS:
			setIdle();			// retry
			break;
		case PROTO_STATE_WFDATA:
			setIdle();
			break;
		case PROTO_STATE_WFACK:
			setIdle();
			break;

		default:
			assert(false);		// invalid
	}
}

void RealTimeSMACLayer::updateNav(simtime_t t)
{
	assert(t > 0);
	simtime_t now = simTime();
	simtime_t nav_left = nav_end_time - now;
	if (nav_state == NAV_CLEAR || t > nav_left){
		setNavTimeout(t);
		nb_received_nav++;
		EV<<"Receive NAV TIMER , Timer during  "<< t << "s"<<endl;
		nav_state = NAV_BUSY;
		nav_end_time = t + now;
	}
}


/**
 * The basic handle transmitDone function.
 * main jobs is done here
 * 1) switch the protocal state ,so the mac layer can keep move
 *
 *
 *
 *
 * todo  here ,if we don't receive message after a period ,
 *        It will simply resent rts event we just need ACK .
 *        So a improvement can be found here
 *
 *        the wait period it set to a simple time
 *
 **/
void RealTimeSMACLayer::transmitDone()
{
	switch (proto_state){
		// It is a problem that eval the Wait timeout
		case PROTO_STATE_SEND_RTS:
			proto_state = PROTO_STATE_WFCTS;
			switchRadio(Radio::RX);;
			break;
		case PROTO_STATE_SEND_CTS:
			proto_state = PROTO_STATE_WFDATA;
			switchRadio(Radio::RX);
			break;
		case PROTO_STATE_SEND_DATA:
			proto_state = PROTO_STATE_WFACK;
			//broadcast doesn't need acknowledge
			if(tx_msgQuene.front()->getDestAddr() ==-1){
				RSMacMsg* msgfree = tx_msgQuene.front();
				tx_msgQuene.pop_front();
				delete msgfree;
				setIdle(); //go on send msg

			}else{
				switchRadio(Radio::RX);
			}
			break;
		case PROTO_STATE_SEND_SYNC:
		case PROTO_STATE_SEND_ACK:
			setIdle();		//go on send msg
			break;
		default:
			assert(false);		// unknown
	}
}

////////////Timeout Functions //////////////////////////

void RealTimeSMACLayer::setProtocolTimeout(simtime_t t)
{	setTimeout(t,TIMER_PROTOCOL);
}

void RealTimeSMACLayer::setNavTimeout(simtime_t t)
{	setTimeout(t,TIMER_NAV);
}

void RealTimeSMACLayer::setSchedTimeout(simtime_t t)
{	setTimeout(t,TIMER_SCHED);
}

void RealTimeSMACLayer::setTimeout(simtime_t ticks, int which)
{
	assert(ticks>0);
	assert(which >= 0 && which < TIMERS);
	//ev << "which = "<<which<<"\n";
	assert(timeout_msg[which]);
	cancelTimeout(which);
	// the actual timeout occurs at the next tb tick
	simtime_t now = simTime() + clock_skew;
	simtime_t then = now + ticks;
	simtime_t thenTime = then-clock_skew+0.0001;
	assert(thenTime > simTime());
	scheduleAt(thenTime, timeout_msg[which]);
}

void RealTimeSMACLayer::cancelTimeout(int which) {
	assert(timeout_msg);
	assert(which>=0 && which < TIMERS);
	if(timeout_msg[which]!=NULL && timeout_msg[which]->isScheduled())
		cancelEvent(timeout_msg[which]);
}

/**
 *  Return a time-out value for a type of frame. Called by
 *  transmitDone etc. There will be a DELAY margin here
 */
simtime_t RealTimeSMACLayer::WaitTimeOut(SmacMessageKinds type)
{
    simtime_t time_out = 0;
    switch (type)
    {
    case DATA:
        time_out = packetDuration(MAX_MSG_LEN, bitrate) +DATA_CONTEND_TIME + DELAY ; //we used the max len as the wait timeout
        break;
    case ACK:
    	time_out = packetDuration(LENGTH_ACK,bitrate)+ ACK_CONTEND_TIME+ DELAY;
    	break;
    case CTS:
    	time_out = packetDuration(LENGTH_CTS,bitrate)+ CTS_CONTEND_TIME+ DELAY;
    	break;
    default:
        EV << "Unused frame type was given when calling timeOut(), this should not happen!\n";
    }
    EV<< "wait until "  <<time_out << "s"<<endl;
    return time_out ; //Make a margin here
}

simtime_t RealTimeSMACLayer::packetDuration(double bits, double br)
{
    return bits / br ;
}

int RealTimeSMACLayer::isSameSchedule(simtime_t time1, simtime_t time2)
{
	simtime_t offset = time1 - time2;
	if(offset<0)
		offset = 0 - offset;
	EV<< "offset" << offset <<"allowDrift" <<allowDrift <<endl;
	return offset < allowDrift;
}



RSMacMsg * RealTimeSMACLayer::encapsMsg(cPacket * netw)
{

	RSMacMsg *pkt = new RSMacMsg(netw->getName());
    // headerLength, including final CRC-field AND the phy header length!
    pkt->setBitLength(SMAC_HEARDLENGTH+netw->getBitLength());
    pkt->setRetry(false);                 // this is not a retry
    if(fsc <= 0) fsc = 1;
    // copy dest address from the Control Info attached to the network
    // mesage by the network layer
    NetwToMacControlInfo* cInfo = static_cast<NetwToMacControlInfo*>(
												netw->removeControlInfo());
    EV <<"CInfo removed, mac addr="<< cInfo->getNextHopMac()<<endl;
    pkt->setDestAddr(cInfo->getNextHopMac());
    //set the src address to own mac address (nic module id())
    pkt->setSrcAddr(myMacAddr);

    //encapsulate the network packet
    pkt->encapsulate(netw);
    EV <<"pkt encapsulated, length: " << pkt->getBitLength() << "\n";
    //delete the control info
    delete cInfo;
    return pkt;
}

//TODO: See if we can use the BaseMacLayers decapsMsg-method here
cMessage *RealTimeSMACLayer::decapsMsg(RSMacMsg *frame) {
    cMessage *m = frame->decapsulate();
    m->setControlInfo(new MacToNetwControlInfo(frame->getSrcAddr(), 0));
    EV << " message decapsulated " << endl;
    return m;
}

void RealTimeSMACLayer::attachSignal(RSMacMsg* macPkt,simtime_t startTime){
	//calc signal duration
	simtime_t duration = macPkt->getBitLength() / bitrate;
	//create signal
	Signal* s = createSignal(startTime, duration, txPower, bitrate);
	//create and initialize control info
	MacToPhyControlInfo* ctrl = new MacToPhyControlInfo(s);
	macPkt->setControlInfo(ctrl);
}


void RealTimeSMACLayer::switchRadio(Radio::RadioState state){
	EV<<"Switching from" << getStateString((Radio::RadioState)phy->getRadioState())
					<< "  to"  << getStateString(state) << endl;
	if(phy->getRadioState()==state){
		return;
	}
	phy->setRadioState(state);

}

std::string RealTimeSMACLayer::getStateString(Radio::RadioState state){
	switch(state){
		case Radio::RX: return " RX ";
		case Radio::TX: return " TX ";
		case Radio::SLEEP: return " SLEEP ";
		case Radio::SWITCHING: return " SWITCHING ";
		default: break;
	}
	return " Others ";
}

bool RealTimeSMACLayer::prorityComp(const RSMacMsg* lmsg,const RSMacMsg* rmsg){
	return lmsg->getPriorty() < rmsg->getPriorty();
}

void RealTimeSMACLayer::dumpQueue(std::string putsFronts){
	EV<<putsFronts;
	SMacMsgList::iterator it;
	for(it = tx_msgQuene.begin(); it != tx_msgQuene.end(); ++it)
	{
		EV<<(*it)->getPriorty();
	}
	EV<<endl;
}
